﻿extern alias RoutineBase1120;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Citi.Helpers;
using Citi.Scheduler.Domain;
using Citi.Scheduler.WebUi.Models;
using System.Reflection;

namespace Citi.Scheduler.WebUi.Controllers
{
    public class RoutineParameterController : ControllerBase<RoutineParameterModel, RoutineParameter>
    {
        private static IEnumerable<RoutineBase1120::Citi.RoutineBase.RoutineParameter> Parameters { get; set; }

        public ActionResult Save(FormCollection collection)
        {
            var routineId = int.Parse(collection["item.RoutineId"].Split(',')[0]);
            collection.Remove("RoutineId");
            var routine = new Routine().SelectById<Routine>(routineId);
            var parameters = GetParameters(routineId);
            var schedulerApplication = new Application().SelectAll<Application>().FirstOrDefault(x => x.Abbreviation == "Sch");

            var values = collection["item.Value"].Split(',');
            var index = 0;

            foreach (var value in values)
            {
                var valueReplaced =  value.Replace("||&||", ",");
        
                var parameter = parameters.ElementAt(index);
                var dbParameter = routine.RoutineParameters.FirstOrDefault(x => x.Name == parameter.Name);

                if (!string.IsNullOrWhiteSpace(valueReplaced))
                {
                    if (dbParameter == null)
                        dbParameter = new RoutineParameter
                            {
                                Application = schedulerApplication,
                                Name = parameter.Name,
                                Routine = routine,
                                Value = valueReplaced
                            };
                    else
                        dbParameter.Value = valueReplaced;

                    dbParameter.Save(dbParameter);
                }
                else
                {
                    if (dbParameter != null)
                        dbParameter.Delete(dbParameter);
                }
                index++;
            }

            //routine.Save(routine);

            return RedirectToAction("Form", "Routine");
        }

        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public ActionResult Index(int routineId)
        {
            Parameters = null;
            var parameters = GetParameters(routineId);

            if (parameters == null)
                return PartialView();

            var routine = new Routine().SelectById<Routine>(routineId);

            return PartialView(parameters.Select(x => new RoutineBaseParameterModel
            {
                Description = x.Description,
                Name = x.Name,
                Nullable = x.Nullable,
                Required = x.Required,
                RoutineId = routineId,
                Type = x.Type,
                Value = routine.RoutineParameters.ToList().FirstOrDefault(y => y.Name == x.Name) == null
                    ? string.Empty
                    : routine.RoutineParameters.ToList().First(y => y.Name == x.Name).Value
            }));
        }

        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public IEnumerable<RoutineBase1120::Citi.RoutineBase.RoutineParameter> GetParameters(int routineId)
        {
            if (Parameters != null) return Parameters;
            try
            {
                using (NetworkShareAccesser.Access(ServerName, NetworkUser, NetworkPassword))
                {
                    var routine = new Routine().SelectById<Routine>(routineId);

                    var version = routine.LibraryVersion;
                    var pathLibrary = Path.Combine(DllFolder, version.LibraryId.ToString(), ((LibraryType)version.Type).ToString(), version.Version, version.LibraryFile);
                    var assemblyName = AssemblyName.GetAssemblyName(pathLibrary);
                    var domain = AppDomain.CurrentDomain;
                    var dll = domain.Load(assemblyName);
                    var pathAssemblies = Path.GetDirectoryName(pathLibrary);
                    var referencedAssemblies = dll.GetReferencedAssemblies().ToList();
                    var assembliesInFolder = new DirectoryInfo(pathAssemblies).GetFiles();
                    var executionClass = dll.GetExportedTypes().FirstOrDefault(x => RoutineBaseTypes.Any(y => y.IsAssignableFrom(x)) && x.Name == routine.Class);

                    var routineBaseDll = referencedAssemblies.FirstOrDefault(x => x.FullName.Contains("Citi.RoutineBase"));

                    if (routineBaseDll == null)
                        return null;

                    domain.AssemblyResolve += (sender, args) =>
                    {
                        var referencedAssembly = assembliesInFolder.FirstOrDefault(x => x.Name == args.Name);
                        return referencedAssembly == null ? null : Assembly.Load(referencedAssembly.FullName);
                    };

                    var executable = Activator.CreateInstance(executionClass);

                    var parameters = executable.GetType().GetProperty("Parameters");

                    if (parameters == null)
                        return null;

                    Parameters = (IEnumerable<RoutineBase1120::Citi.RoutineBase.RoutineParameter>)parameters.GetValue(executable, null);
                    return Parameters;
                }
            }
            catch
            {
                return null;
            }
        }

        public ActionResult ValidateParameter(string value, int index, int routineId)
        {
            var parameters = GetParameters(routineId);

            var parameter = parameters.ElementAt(index);

            if (string.IsNullOrWhiteSpace(value) && (!parameter.Nullable || parameter.Required))
                return Json(new { validated = false });

            if (string.IsNullOrWhiteSpace(value)) return Json(new { validated = true });

            var valueConverted = RoutineParameter.FillVariables(value);

            return Json(new { validated = valueConverted.ConvertType(parameter.Type) != null });
        }
    }
}